use diesel::{prelude::*, query_builder::InsertStatement, query_dsl::methods::ExecuteDsl};

use crate::database::DbError;

pub fn create<T, U>(conn: &mut MysqlConnection, table: T, new_item: U) -> Result<(), DbError>
where
    T: Table,
    U: Insertable<T>,
    InsertStatement<T, U::Values>: ExecuteDsl<MysqlConnection>,
{
    conn.transaction(|conn| {
        diesel::insert_into(table).values(new_item).execute(conn)?;
        Ok(())
    })
}

#[macro_export]
macro_rules! db_create {
    ($table:ident, $model:ident, $new_model:ident, $fn:ident) => {
        pub fn $fn(conn: &mut MysqlConnection, new_item: $new_model) -> Result<i32, DbError> {
            conn.transaction(|conn| {
                crud::create::create(conn, $table::table, new_item)?;
                let added_item = crud::read::reads_offset::<_, $model, _, _>(
                    conn,
                    $table::table,
                    $model::as_select(),
                    $table::id.desc(),
                    1,
                    0,
                )?;
                Ok(added_item[0].id)
            })
        }
    };
}

#[macro_export]
macro_rules! db_creates {
    ($table:ident, $model:ident, $new_model:ident, $fn:ident) => {
        pub fn $fn(conn: &mut MysqlConnection, new_items: Vec<$new_model>) -> Result<(), DbError> {
            conn.transaction(|conn| crud::create::create(conn, $table::table, new_items))
        }
    };
}

#[macro_export]
macro_rules! test_db_create {
    () => {
        #[test]
        fn test_create() {
            let mut conn = establish_connection();
            conn.test_transaction::<_, diesel::result::Error, _>(|conn| {
                let (added_id, _, _) = insert_test_data(conn);
                assert!(added_id > 0);
                Ok(())
            });
        }
    };
}
